diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
index 1c4e92b..64553a8 100644
--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
+++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/Makefile
@@ -6,12 +6,12 @@
 
 subdir-ccflags-y += -I$(src)
 
-obj-$(CONFIG_MLX5_CORE) += mlx5_core.o
+obj-$(CONFIG_MLX5_CORE) += mlx5_core$(NETMAP_DRIVER_SUFFIX).o
 
 #
 # mlx5 core basic
 #
-mlx5_core-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
+mlx5_core$(NETMAP_DRIVER_SUFFIX)-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
 		health.o mcg.o cq.o srq.o srq_exp.o alloc.o qp.o port.o mr.o pd.o \
 		mad.o transobj.o vport.o sriov.o fs_cmd.o fs_core.o \
 		fs_counters.o rl.o lag.o dev.o wq.o lib/gid.o  \
@@ -19,50 +19,49 @@ mlx5_core-y :=	main.o cmd.o debugfs.o fw.o eq.o uar.o pagealloc.o \
 		devcom.o en_diag.o params.o fs_debugfs.o nvmf.o crdump.o icmd.o capi.o diag/tracer.o diag/diag_cnt.o \
 		eswitch_devlink_compat.o
 
-
 #
 # Netdev basic
 #
-mlx5_core-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
+mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CORE_EN) += en_main.o en_common.o en_fs.o en_ethtool.o \
 		en_tx.o en_rx.o en_dim.o en_txrx.o en/xdp.o en_stats.o en_sysfs.o en_ecn.o \
 		en_selftest.o en/port.o en_debugfs.o en_sniffer.o
 
 #
 # Netdev extra
 #
-mlx5_core-$(CONFIG_MLX5_EN_ARFS)     += en_arfs.o
-mlx5_core-$(CONFIG_MLX5_EN_RXNFC)    += en_fs_ethtool.o
-mlx5_core-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o en/port_buffer.o
-mlx5_core-$(CONFIG_MLX5_ESWITCH)     += en_rep.o en_tc.o lag_mp.o
+mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_ARFS)     += en_arfs.o
+mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_RXNFC)    += en_fs_ethtool.o
+mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CORE_EN_DCB) += en_dcbnl.o en/port_buffer.o
+mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ESWITCH)     += en_rep.o en_tc.o lag_mp.o
 
 #
 # Core extra
 #
-mlx5_core-$(CONFIG_MLX5_ESWITCH)   += eswitch.o eswitch_offloads.o ecpf.o
-mlx5_core-$(CONFIG_MLX5_MPFS)      += lib/mpfs.o
+mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ESWITCH)   += eswitch.o eswitch_offloads.o ecpf.o
+mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_MPFS)      += lib/mpfs.o
 ifneq ($(CONFIG_VXLAN),)
-	mlx5_core-y		+= lib/vxlan.o
+	mlx5_core$(NETMAP_DRIVER_SUFFIX)-y		+= lib/vxlan.o
 endif
 ifneq ($(CONFIG_PTP_1588_CLOCK),)
-	mlx5_core-y		+= lib/clock.o
+	mlx5_core$(NETMAP_DRIVER_SUFFIX)-y		+= lib/clock.o
 endif
 
 #
 # Ipoib netdev
 #
-mlx5_core-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o ipoib/ipoib_vlan.o
+mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_CORE_IPOIB) += ipoib/ipoib.o ipoib/ethtool.o ipoib/ipoib_vlan.o
 
 #
 # Accelerations & FPGA
 #
-mlx5_core-$(CONFIG_MLX5_ACCEL) += accel/ipsec.o accel/tls.o
+mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_ACCEL) += accel/ipsec.o accel/tls.o
 
-mlx5_core-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o \
+mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_FPGA) += fpga/cmd.o fpga/core.o fpga/conn.o fpga/sdk.o \
 			fpga/ipsec.o fpga/tls.o fpga/trans.o fpga/xfer.o
 
-mlx5_core-$(CONFIG_MLX5_EN_IPSEC) += en_accel/ipsec.o en_accel/ipsec_rxtx.o \
+mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_IPSEC) += en_accel/ipsec.o en_accel/ipsec_rxtx.o \
 				     en_accel/ipsec_stats.o
 
-mlx5_core-$(CONFIG_MLX5_EN_TLS) += en_accel/tls.o en_accel/tls_rxtx.o en_accel/tls_stats.o
+mlx5_core$(NETMAP_DRIVER_SUFFIX)-$(CONFIG_MLX5_EN_TLS) += en_accel/tls.o en_accel/tls_rxtx.o en_accel/tls_stats.o
 
 CFLAGS_tracepoint.o := -I$(src)
diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
index ca7eb20..27dc8e4 100644
--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
+++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_main.c
@@ -57,6 +57,16 @@
 #include "en/port.h"
 #include "en/xdp.h"
 
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+/*
+ * mlx5_netmap_linux.h contains functions for netmap support
+ * that extend the standard driver.
+ */
+#define NETMAP_MLX5_MAIN
+#define DEV_NETMAP
+#include "mlx5_netmap_linux.h"
+#endif
+
 struct mlx5e_rq_param {
 	u32			rqc[MLX5_ST_SZ_DW(rqc)];
 	struct mlx5_wq_param	wq;
@@ -89,6 +99,9 @@ struct mlx5e_channel_param {
 
 bool mlx5e_check_fragmented_striding_rq_cap(struct mlx5_core_dev *mdev)
 {
+#ifdef DEV_NETMAP
+	return 0;
+#endif
 	bool striding_rq_umr = MLX5_CAP_GEN(mdev, striding_rq) &&
 		MLX5_CAP_GEN(mdev, umr_ptr_rlky) &&
 		MLX5_CAP_ETH(mdev, reg_umr_sq);
@@ -877,6 +890,10 @@ static int mlx5e_alloc_rq(struct mlx5e_channel *c,
 		rq->dim_obj.dim.mode = NET_DIM_CQ_PERIOD_MODE_START_FROM_EQE;
 	}
 
+#ifdef DEV_NETMAP
+	mlx5e_netmap_configure_rx_ring(rq, rq->ix);
+#endif /* DEV_NETMAP */
+
 	return 0;
 
 err_free:
@@ -1098,6 +1115,12 @@ static int mlx5e_wait_for_min_rx_wqes(struct mlx5e_rq *rq, int wait_time)
 	unsigned long exp_time = jiffies + msecs_to_jiffies(wait_time);
 	struct mlx5e_channel *c = rq->channel;
 
+#ifdef DEV_NETMAP
+	struct netmap_adapter *na = NA(c->netdev);
+	if (nm_netmap_on(na) && na->rx_rings[rq->ix]->nr_mode == NKR_NETMAP_ON)
+		return 0; /* no need to wait when netmap has built wqes */
+#endif
+
 	u16 min_wqes = mlx5_min_rx_wqes(rq->wq_type, mlx5e_rqwq_get_size(rq));
 
 	do {
@@ -1140,6 +1163,10 @@ static void mlx5e_free_rx_descs(struct mlx5e_rq *rq)
 
 		while (!mlx5_wq_cyc_is_empty(wq)) {
 			wqe_ix = mlx5_wq_cyc_get_tail(wq);
+#ifdef DEV_NETMAP
+			struct netmap_adapter *na = NA(rq->channel->netdev);
+			if (!nm_netmap_on(na) || na->rx_rings[rq->ix]->nr_mode == NKR_NETMAP_OFF)
+#endif
 			rq->dealloc_wqe(rq, wqe_ix);
 			mlx5_wq_cyc_pop(wq);
 		}
@@ -1252,6 +1279,9 @@ static void mlx5e_activate_rq(struct mlx5e_rq *rq)
 
 	u16 pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
 
+#ifdef DEV_NETMAP
+	if (!nm_netmap_on(NA(rq->channel->netdev)) || NA(rq->channel->netdev)->rx_rings[rq->ix]->nr_mode == NKR_NETMAP_OFF)
+#endif
 	set_bit(MLX5E_RQ_STATE_ENABLED, &rq->state);
 	sq->db.ico_wqe[pi].opcode     = MLX5_OPCODE_NOP;
 	nopwqe = mlx5e_post_nop(wq, sq->sqn, &sq->pc);
@@ -1471,6 +1501,11 @@ static int mlx5e_alloc_txqsq(struct mlx5e_channel *c,
 	INIT_WORK(&sq->dim_obj.dim.work, mlx5e_tx_dim_work);
 	sq->dim_obj.dim.mode = params->tx_cq_moderation.cq_period_mode;
 
+#ifdef DEV_NETMAP
+	if (mlx5e_netmap_configure_tx_ring(c->priv, txq_ix))
+		return 0;
+#endif /* DEV_NETMAP */
+
 	return 0;
 
 err_sq_wq_destroy:
@@ -1685,6 +1720,9 @@ static void mlx5e_deactivate_txqsq(struct mlx5e_txqsq *sq)
 	netif_tx_disable_queue(sq->txq);
 
 	/* last doorbell out, godspeed .. */
+#ifdef DEV_NETMAP
+	if (!nm_netmap_on(NA(sq->txq->dev))) // TODO
+#endif
 	if (mlx5e_wqc_has_room_for(wq, sq->cc, sq->pc, 1)) {
 		u16 pi = mlx5_wq_cyc_ctr2ix(wq, sq->pc);
 		struct mlx5e_tx_wqe *nop;
@@ -1702,6 +1740,12 @@ static void mlx5e_close_txqsq(struct mlx5e_txqsq *sq)
 	struct mlx5_rate_limit rl = {0};
 
 	cancel_work_sync(&sq->dim_obj.dim.work);
+
+#ifdef DEV_NETMAP
+	if (nm_netmap_on(NA(sq->txq->dev))) // TODO
+		mlx5e_netmap_tx_flush(sq); /* handle any CQEs */
+#endif
+
 	mlx5e_destroy_sq(mdev, sq->sqn);
 	if (sq->rate_limit) {
 		rl.rate = sq->rate_limit;
@@ -1720,6 +1764,10 @@ static int mlx5e_wait_for_sq_flush(struct mlx5e_txqsq *sq)
 			return 0;
 
 		msleep(20);
+#ifdef DEV_NETMAP
+		if (nm_netmap_on(NA(sq->txq->dev))) // TODO
+			mlx5e_netmap_tx_flush(sq); /* handle any CQEs */
+#endif
 	}
 
 	netdev_err(sq->channel->netdev,
@@ -3539,6 +3587,10 @@ int mlx5e_open_locked(struct net_device *netdev)
 	if (priv->profile->update_carrier)
 		priv->profile->update_carrier(priv);
 
+#ifdef DEV_NETMAP
+	netmap_enable_all_rings(netdev); /* NOP if netmap not in use */
+#endif
+
 	return 0;
 
 err_clear_state_opened_flag:
@@ -3583,6 +3635,10 @@ int mlx5e_close_locked(struct net_device *netdev)
 
 	clear_bit(MLX5E_STATE_OPENED, &priv->state);
 
+#ifdef DEV_NETMAP
+	netmap_disable_all_rings(netdev);
+#endif
+
 	if (MLX5E_GET_PFLAG(&priv->channels.params, MLX5E_PFLAG_SNIFFER)) {
 		mlx5e_sniffer_stop(priv);
 		MLX5E_SET_PFLAG(&priv->channels.params, MLX5E_PFLAG_SNIFFER, 0);
@@ -6405,6 +6461,10 @@ void mlx5e_destroy_netdev(struct mlx5e_priv *priv)
 	const struct mlx5e_profile *profile = priv->profile;
 	struct net_device *netdev = priv->netdev;
 
+#ifdef DEV_NETMAP
+	netmap_detach(netdev);
+#endif /* DEV_NETMAP */
+
 	if (profile->cleanup)
 		profile->cleanup(priv);
 	free_netdev(netdev);
@@ -6505,6 +6565,11 @@ static void *mlx5e_add(struct mlx5_core_dev *mdev)
 	mlx5e_dcbnl_init_app(priv);
 #endif
 #endif
+
+#ifdef DEV_NETMAP
+	mlx5e_netmap_attach(priv);
+#endif /* DEV_NETMAP */
+
 	return priv;
 
 err_unregister_netdev:
diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
index c4e7420..b61fd09 100644
--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
+++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_rx.c
@@ -49,6 +49,14 @@
 #include "lib/clock.h"
 #include "en/xdp.h"
 
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+/*
+ * mlx5_netmap_linux.h contains functions for netmap support
+ * that extend the standard driver.
+ */
+#include "mlx5_netmap_linux.h"
+#endif
+
 static inline bool mlx5e_rx_hw_stamp(struct hwtstamp_config *config)
 {
 	return config->rx_filter == HWTSTAMP_FILTER_ALL;
@@ -154,7 +162,7 @@ static inline u32 mlx5e_decompress_cqes_cont(struct mlx5e_rq *rq,
 	return cqe_count;
 }
 
-static inline u32 mlx5e_decompress_cqes_start(struct mlx5e_rq *rq,
+u32 mlx5e_decompress_cqes_start(struct mlx5e_rq *rq,
 					      struct mlx5e_cq *cq,
 					      int budget_rem)
 {
@@ -1630,6 +1638,13 @@ int mlx5e_poll_rx_cq(struct mlx5e_cq *cq, int budget)
 		priv = netdev_priv(rq->netdev);
 #endif
 
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+	int dummy;
+	int nm_irq = netmap_rx_irq(rq->netdev, rq->ix, &dummy);
+	if (nm_irq != NM_IRQ_PASS)
+		return (nm_irq == NM_IRQ_RESCHED) ? budget : 1;
+#endif
+
 	if (unlikely(!test_bit(MLX5E_RQ_STATE_ENABLED, &rq->state)))
 		return 0;
 
diff --git a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
index b54766b..fe80042 100644
--- a/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
+++ b/mlx5/drivers/net/ethernet/mellanox/mlx5/core/en_tx.c
@@ -38,6 +38,15 @@
 #include "en_accel/en_accel.h"
 #include "lib/clock.h"
 
+
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+/*
+ * mlx5_netmap_linux.h contains functions for netmap support
+ * that extend the standard driver.
+ */
+#include "mlx5_netmap_linux.h"
+#endif
+
 #define MLX5E_SQ_NOPS_ROOM  MLX5_SEND_WQE_MAX_WQEBBS
 
 #if defined(CONFIG_MLX5_EN_TLS) && defined(HAVE_UAPI_LINUX_TLS_H)
@@ -630,6 +639,11 @@ bool mlx5e_poll_tx_cq(struct mlx5e_cq *cq, int napi_budget)
 
 	sq = container_of(cq, struct mlx5e_txqsq, cq);
 
+#if defined(CONFIG_NETMAP) || defined(CONFIG_NETMAP_MODULE)
+	if (netmap_tx_irq(sq->channel->netdev, sq->channel->ix) != NM_IRQ_PASS)
+		return false;
+#endif
+
 	if (unlikely(!test_bit(MLX5E_SQ_STATE_ENABLED, &sq->state)))
 		return false;
 
@@ -760,15 +774,17 @@ void mlx5e_free_txqsq_descs(struct mlx5e_txqsq *sq)
 			continue;
 		}
 
-		for (i = 0; i < wi->num_dma; i++) {
-			struct mlx5e_sq_dma *dma =
-				mlx5e_dma_get(sq, sq->dma_fifo_cc++);
+		if (!nm_netmap_on(NA(sq->txq->dev))) {
+			/* do not free skbs in netmap mode */
+			for (i = 0; i < wi->num_dma; i++) {
+				struct mlx5e_sq_dma *dma =
+					mlx5e_dma_get(sq, sq->dma_fifo_cc++);
 
-			mlx5e_tx_dma_unmap(sq->pdev, dma);
+				mlx5e_tx_dma_unmap(sq->pdev, dma);
+			}
+			dev_kfree_skb_any(skb);
 		}
-
-		dev_kfree_skb_any(skb);
-		sq->cc += wi->num_wqebbs;
+        sq->cc += wi->num_wqebbs;
 	}
 }
 
